/*
 * @Date         : 2022-06-10 09:53:35
 * @LastEditors  : zu1662
 * @LastEditTime : 2022-07-22 13:43:51
 * @Description  : User Service
 * 
 * Copyright © 2022 by zu1662, All Rights Reserved. 
 */
import { Injectable, Logger } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { ConfigService } from "@nestjs/config";
import { Repository } from "typeorm";
import { UserEntity } from "./user.entity";
import { DebuggerService } from "src/debugger/service/debugger.service";
import { IUserCheckExist, IUserListInfo } from "./user.interface";
import { UserListSerialization } from "./serialization/user.list.serialization";
import { plainToInstance } from "class-transformer";
import { UserDetailSerialization } from "./serialization/user.detail.serialization";
import { HelperHashService } from "src/utils/helper/service/helper.hash.service";


@Injectable()
export class UserService {

  constructor(
    @InjectRepository(UserEntity)
    private readonly userRepository: Repository<UserEntity>,
    private readonly configService: ConfigService,
    private readonly debuggerService: DebuggerService,
    private readonly helperHashService: HelperHashService,
  ) {
    this.initAdminUser()
  }

  // 初始化管理员用户
  async initAdminUser(){
    const logger = new Logger();
    const username = this.configService.get<string>("app.admin.username")
    const password = this.configService.get<string>("app.admin.password")
    const existAdminUser = await this.userRepository.findOne({ where: { name: username }})
    if(existAdminUser) {
      const matchPassword: boolean = await this.validateUser(password, existAdminUser.password);
      if(matchPassword) {
        logger.log(`管理员账户已经存在，用户名：${username}，密码：${password}，请及时登录系统修改默认密码`, 'NestApplication');
      }
    } else {
      const hashPassword = await this.createPassword(password)
      await this.createUser({ name: username, password: hashPassword, role: 'admin' })
      logger.log(`管理员账户创建成功，用户名：${username}，密码：${password}，请及时登录系统修改默认密码`, 'NestApplication');
    }
  }

  // 所有用户
  async findAll(queryParams: Record<string, any>):Promise<IUserListInfo> {
    const { skip, perPage, search, sort, availableSearch, filters } = queryParams
    
    const query = this.userRepository.createQueryBuilder('user').orderBy(`user.${sort.field}`, sort.sortType);
    // 如果 search 存在，则模糊搜索，filters 为精确到字段搜索
    if(search && typeof search === 'string') {
      query.andWhere(`CONCAT(${availableSearch.join(',')}) LIKE "%${search}%"`)
    } else if (filters && typeof filters === 'object') {
      availableSearch.forEach(key => {
        if(filters[key]) {
          query.andWhere(`${key} LIKE :${key}`).setParameter(`${key}`, `%${filters[key]}%`);
        }
      })
    }
    const totalData = await query.getCount()
    query.skip(skip);
    query.take(perPage);
    return {
      totalData,
      data: await query.getMany()
    }
  }

  // 获取用户详情
  async findById(id: string): Promise<UserEntity> {
    return await this.userRepository.findOne({where: { id }})
  }

  // 根据用户名查找用户
  async findByName(name: string): Promise<UserEntity> {
    return await this.userRepository.findOne({where: { name }})
  }

  // 根据用户手机号查找用户
  async findByPhone(phone: string): Promise<UserEntity> {
    return await this.userRepository.findOne({where: { phone }})
  }

  // 更新用户密码
  async updatePassword(id: string, password: string): Promise<UserEntity> {
    const user: UserEntity = await this.findById(id)
    const newUser = await this.userRepository.merge(user, { password })
    return await this.userRepository.save(newUser)
  }

  // 检查用户关键是否存在
  async checkExist(email: string, phone: string, id?: string): Promise<IUserCheckExist> {
    const userEntityMail = await this.userRepository.findOne({ where: { email, id }})
    const userNetityPhone = await this.userRepository.findOne({ where: { phone, id }})
    return {
      email: !!userEntityMail,
      phone: !!userNetityPhone
    }
  }

  // 创建用户
  async createUser(user: Partial<UserEntity>): Promise<UserEntity> {
    const newUser = await this.userRepository.create(user);
    return await this.userRepository.save(newUser);
  }

  // 创建用户
  async updateUser(user: Partial<UserEntity>): Promise<Partial<UserEntity>> {
    const oldUser = await this.userRepository.findOne({ where: { id: user.id }})
    const newUser = await this.userRepository.merge(oldUser, user);
    const saveUser = await this.userRepository.save(newUser);
    return {
      id: saveUser.id,
      name: saveUser.name
    }
  }

  async serializationList(data: UserEntity[]): Promise<UserListSerialization[]> {
    return plainToInstance(UserListSerialization, data);
  }

  async serializationDetail(data: UserEntity): Promise<UserDetailSerialization> {
    return plainToInstance(UserDetailSerialization, data);
  }

  async validateUser(passwordString: string, passwordHash: string): Promise<boolean> {
    return this.helperHashService.bcryptCompare(passwordString, passwordHash);
  }

  async createPassword(password: string): Promise<string> {
    const saltLength: number = this.configService.get<number>("auth.password.saltLength");

    const salt: string = await this.helperHashService.randomSalt(saltLength);

    const passwordHash = await this.helperHashService.bcrypt(password, salt);
    return passwordHash
  }

}
